#include <iostream>
#include <vector>

using namespace std;

struct sprite
{
	char spriteID[50];
	char spriteName[50];
};

//Check exist file?
int IsExist(char* filename)
{
	FILE* file = fopen(filename, "r");
	if(file)
	{
		fclose(file);
		return 1;
	}
	return 0;
}

//cut space before of string
char* CutSpaceBefore( char * str )
{
	while ( str[0] == ' ' )
	{
		for (int i = 0; i < strlen( str ) - 1; i++)
			str[i] = str[i + 1];
		str[strlen( str ) - 1] = '\0';
	}
	return str;
}

//convert char ABCDF to number
int SwitchCharToNumver ( char ch )
{
	switch (ch)
	{
	case 'A':
	case 'a':
		return 10;
	case 'B':
	case 'b':
		return 11;
	case 'C':
	case 'c':
		return 12;
	case 'D':
	case 'd':
		return 13;
	case 'E':
	case 'e':
		return 14;
	case 'F':
	case 'f':
		return 15;
	default:
		return (ch - '0');
	}
}

//Ox1006 -> 6 not use 0x1 only conver 006
int ConvertHexToDec (char* hec )
{
	int a2, a1, a0;
	a2 = SwitchCharToNumver ( hec[3] );
	a1 = SwitchCharToNumver ( hec[4] );
	a0 = SwitchCharToNumver ( hec[5] );
	
	return ( a2*16*16 + a1*16 + a0 );
}

//Get out put file name
char* GetFileName ( char * fileName )
{
	char* fileOutName; 	
	int i;
	//cut file name to get name of file
	fileOutName = new char[strlen( fileName ) - strlen( ".sprite" ) + strlen( ".pak" )];
	for ( i = 0; i < strlen( fileName ) - strlen( ".sprite" ); i++ )
		fileOutName[i] = fileName[i];
		
	fileOutName[i] = '\0';	
	return fileOutName;
}

//get name of pak
char* GetOutPutPakFileName ( char* spriteID )
{
	char* fileOutName = new char [strlen ( spriteID) + strlen( ".pack" )] ; 	
	strcpy (fileOutName, spriteID );
	fileOutName[strlen ( spriteID ) ] = '.';
	fileOutName[strlen ( spriteID ) + 1] = 'p';
	fileOutName[strlen ( spriteID ) + 2] = 'a';
	fileOutName[strlen ( spriteID ) + 3] = 'c';
	fileOutName[strlen ( spriteID ) + 4] = 'k';	
	fileOutName[strlen ( spriteID ) + 5] = '\0';	
	return fileOutName;
}

//get name of class (.h)
char* GetOutPutClassFileName ( char* spriteID )
{
	char* fileOutName = new char [strlen( spriteID ) + strlen (".h")] ; 		
	strcpy (fileOutName, spriteID );
	fileOutName[strlen( spriteID )] = '.';
	fileOutName[strlen( spriteID )  + 1] = 'h';
	fileOutName[strlen( spriteID )  + 2] = '\0';	
	return fileOutName;
}

//Get name of image
char* GetImageName( char* fileName )
{
	char line[200], temp[100], tempImageName[255], imageName[50];	

	FILE *fIn = fopen( fileName, "r");
	if ( fIn == NULL )
	{
		cout << endl << "\nCan not read file: " << fileName;
		return "";
	}

	while ( !feof ( fIn ) )
	{		
		fgets( line, sizeof( line ),fIn );

		//Print out screen
		//cout<<endl;
		//for ( int i = 0; i < strlen(line); i++ )
			//cout <<" "<< i << ": " << line[i];
		//find with: IMAGE 0x0
		if ( line[4] == 'I' && line[5] == 'M' && line[6] == 'A' && line[7] == 'G' && line[8] == 'E' && line[10] == '0' && line[11] == 'x' && line[12] =='0' )
		{		
			int w, h;
			sscanf(&line[1], "%s" "%s" "%s" "%s" "%s" "%s" "%s" "%s" "%d" "%s" "%d", &temp, &temp, &tempImageName, &temp, &temp, &temp, &temp, &temp, &w, &temp, &h);
			
			//tempImageName with ".../imageName.png"
			//cut "" 

			char temp[50]; 
			for (int i = strlen ( tempImageName ) - 2; i >= 0; i-- )
			{	
				if ( tempImageName[i] == '\\' )
				{
					temp[strlen ( tempImageName ) - 2 - i] = '\0';
					break;
				}
				temp[strlen ( tempImageName ) - 2 - i] = tempImageName[i];
			}

			for (int i = strlen ( temp ) - 1; i >= 0; i-- )
			{	
				
				imageName[strlen ( temp ) - 1 - i] = temp[i];
			}
			imageName[strlen ( temp ) ] = '\0';			
			break;
		}
	}

	fclose ( fIn );

	char* name = new char[strlen (imageName)];
	strcpy (name, imageName);
	return name;
}


//read and write name and size of image
void NameAndSize_Of_Image( char* spriteID, char* fileName )
{
	char line[200], temp[100], tempImageName[255], imageName[50];
	char* outFileName = GetOutPutPakFileName ( spriteID );

	FILE *fIn = fopen( fileName, "r");
	if ( fIn == NULL )
	{
		cout  << endl << "Can not read file: " << fileName;
		return;
	}

	FILE *fOut = fopen( outFileName, "w");

	while ( !feof ( fIn ) )
	{		
		fgets( line, sizeof( line ),fIn );

		//Print out screen
		//cout<<endl;
		//for ( int i = 0; i < strlen(line); i++ )
			//cout <<" "<< i << ": " << line[i];
		//find with: IMAGE 0x0
		if ( line[4] == 'I' && line[5] == 'M' && line[6] == 'A' && line[7] == 'G' && line[8] == 'E' && line[10] == '0' && line[11] == 'x' && line[12] =='0' )
		{		
			int w, h;
			sscanf(&line[1], "%s" "%s" "%s" "%s" "%s" "%s" "%s" "%s" "%d" "%s" "%d", &temp, &temp, &tempImageName, &temp, &temp, &temp, &temp, &temp, &w, &temp, &h);
			
			//tempImageName with ".../imageName.png"
			//cut "" 

			char temp[50]; 
			for (int i = strlen ( tempImageName ) - 2; i >= 0; i-- )
			{	
				if ( tempImageName[i] == '\\' )
				{
					temp[strlen ( tempImageName ) - 2 - i] = '\0';
					break;
				}
				temp[strlen ( tempImageName ) - 2 - i] = tempImageName[i];
			}

			for (int i = strlen ( temp ) - 1; i >= 0; i-- )
			{	
				
				imageName[strlen ( temp ) - 1 - i] = temp[i];
			}
			imageName[strlen ( temp ) ] = '\0';
			
			fprintf( fOut, "IMAGE %s Size %d %d", imageName, w, h);	
			break;
		}
	}
	fclose ( fOut );
	fclose ( fIn );
}


//Read and write modules
void Modules(  char* spriteID, char* fileName )
{
	char line[200];
	char* outFileName = GetOutPutPakFileName ( spriteID );

	FILE *fIn = fopen( fileName, "r");
	if ( fIn == NULL )
	{
		cout << endl << "nCan not read file: " << fileName;
		return;
	}

	FILE *fOut = fopen( outFileName, "a"); //append
	fprintf( fOut, "\n// Modules\n");

	//Get module have max value (ex 0x001A  is max value)

	while ( !feof ( fIn ) )
	{		
		fgets( line, sizeof( line ),fIn );

		//Print out screen
		//cout<<endl;
		//for ( int i = 0; i < strlen(line); i++ )
			//cout <<" "<< i << ": " << line[i];
		
		//find with MD	0x
		if (line[8] == 'M' && line[9] == 'D' && line[11] == '0' && line[12] =='x' && line[18] =='M' && line[19] =='D' && line[20] =='_' && line[21] =='I' && line[22] =='M' && line[23] =='A' )
		{				
			CutSpaceBefore (line );
			//cut MD_IMAGE
			while ( line[9] != '0' )
			{
				for (int i = 9; i < strlen( line ) - 1; i++)
					line[i] = line[i + 1];
				line[strlen( line ) - 1] = '\0';
			}
			line[9]=' ';
			fprintf( fOut, "%s", line );
				
		}	

		if ( line[4] == '}' )
			break;
		memset(line, 0, sizeof(line));
	}
	fclose ( fOut );
	fclose ( fIn );
}

//Read and write frames
void Frames ( char* spriteID, char* fileName )
{
	char line[200], temp[100], frameName[100], frameID[10];
	int numOfFrame;
	
	char* outFileName = GetOutPutPakFileName ( spriteID );
	bool isReadFModule = false;

	FILE *fIn = fopen( fileName, "r");
	if ( fIn == NULL )
	{
		cout << endl << "nCan not read file: " << fileName;
		return;
	}

	FILE *fOut = fopen( outFileName, "a"); //append
	fprintf( fOut, "\n// Frames");

	while ( !feof ( fIn ) )
	{		
		fgets( line, sizeof( line ),fIn );

		//Print out screen
		//cout<<endl;
		//for ( int i = 0; i < strlen(line); i++ )
			//cout <<" "<< i << ": " << line[i];
		
		//find with FRANE
		if ( line[4] == 'F' && line[5] == 'R' && line[6] == 'A' && line[7] =='M' && line[8] =='E' )
		{				
			sscanf( &line[1], "%s" "%s" "%s" "%s" "%s" "%s" "%s" "%s" "%ds",  &temp, &frameName, &temp, &temp, &temp, &frameID,  &temp,  &temp,  &numOfFrame );
			
			//if framName == ""
			if ( frameName[0] == '"' && frameName[1] == '"' ) 
			{
				frameName[0] = 'F';
				frameName[1] = 'R';
				frameName[2] = 'A';
				frameName[3] = 'M';
				frameName[4] = 'E';
				frameName[5] = '_';
				for ( int i = 0; i < strlen( frameID ) - 1; i++ )
					frameName[6 + i] = frameID[i];
				frameName[6 + strlen( frameID ) - 1] = '\0';
			}
			else
			{
				int i;
				for ( i = 0; i < strlen( frameName ) - 1; i++ )
					frameName[i] = frameName[i + 1];
				frameName[i - 1] = '\0';
			}

			fprintf( fOut, "\nFRAME %s %d //name num_frame\n", strupr(frameName), numOfFrame );		//frameID ex: 10,
			isReadFModule = true;
		}	
		
		//Finish a frame
		else if ( isReadFModule )
		{
			if ( line[4] == '}' )
			isReadFModule = false;
			fprintf( fOut, "%s", CutSpaceBefore( line ) );			
		}

		//finish frame
		if ( line[4] == 'A' && line[5] == 'N' && line[6] == 'I' && line[7] =='M' )
			break;
		memset(line, 0, sizeof(line));		
	}
	
	fclose ( fOut );
	fclose ( fIn );
}

//Read and write anims
void Anims( char* spriteID, char* fileName )
{
	char line[200], temp[100], animName[100], animID[10];
	
	char* outFileName = GetOutPutPakFileName ( spriteID );
	bool isReadAFrame = false;
	int amimCount = 0;
	int numofAnim;

	FILE *fIn = fopen( fileName, "r");
	if ( fIn == NULL )
	{
		cout << endl << "Can not read file: " << fileName;
		return;
	}

	FILE *fOut = fopen( outFileName, "a"); //append
	fprintf( fOut, "\n// Anims");

	while ( !feof ( fIn ) )
	{		
		fgets( line, sizeof( line ),fIn );

		//Print out screen
		//cout<<endl;
		//for ( int i = 0; i < strlen(line); i++ )
			//cout <<" "<< i << ": " << line[i];
		
		//find with FRANE
		if ( line[4] == 'A' && line[5] == 'N' && line[6] == 'I' && line[7] =='M' )
		{				
			sscanf( &line[1], "%s" "%s" "%s" "%s" "%s" "%s" "%s" "%s" "%d",  &temp, &animName, &temp, &temp, &temp, &animID, &temp, &temp, &numofAnim );
			
			//if animName == ""
			if ( animName[0] == '"' && animName[1] == '"' ) 
			{
				animName[0] = 'A';
				animName[1] = 'N';
				animName[2] = 'I';
				animName[3] = 'M';
				animName[4] = '_';
				for ( int i = 0; i < strlen( animID ) - 1; i++ )
					animName[5 + i] = animID[i];
				animName[5 + strlen( animID ) - 1] = '\0';
			}
			else
			{
				int i;
				for ( i = 0; i < strlen( animName ) - 1; i++ )
					animName[i] = animName[i + 1];
				animName[i - 1] = '\0';
			}

			fprintf( fOut, "\nANIM %s %d // name num_anim\n", strupr(animName), numofAnim );		//frameID ex: 10,
			isReadAFrame = true;
		}	
		
		//Finish a frame
		else if ( isReadAFrame )
		{
			if ( line[4] == '}' )
			isReadAFrame = false;
			fprintf( fOut, "%s", CutSpaceBefore( line ) );			
		}
		amimCount++;
		memset(line, 0, sizeof(line));		
	}
	
	fclose ( fOut );
	fclose ( fIn );
}

void MaxValue_MD_FR_AN ( char* spriteID )
{
	char line[200], temp[100], value[10];
	int arrayModule[300], arrayFrame[300], arrayAnim[300];
	int countModule, countFrame, countAnim;
	countModule = countFrame = countAnim = 0;
	
	char* outFileName = GetOutPutPakFileName ( spriteID );
	FILE* f = fopen ( outFileName, "r");
	while ( !feof (f) )
	{
		fgets( line , sizeof (line), f );
		//module
		if ( line [0] == 'M' && line [1] == 'D' )
		{
			sscanf( &line[1], "%s" "%s", &temp, &value );
			arrayModule[countModule++] = ConvertHexToDec( value );
		}
		//frame starts with 0x2000
		else if ( line [0] == '0' && line [1] == 'x' &&  line [2] == '2' )
		{
			//sscanf( &line[1], "%s", &value );
			arrayFrame[countFrame++] = ConvertHexToDec( line );
		}
		//anim starts with 0x3000
		else if ( line [0] == '0' && line [1] == 'x' &&  line [2] == '3' )
		{
			//sscanf( &line[1], "%s", &value );
			arrayAnim[countAnim++] = ConvertHexToDec( line );
		}

		memset( line, 0, sizeof(line) );
		memset( value, 0, sizeof(value) );
	}
	fclose (f);

	FILE* fOut = fopen ( outFileName, "a");

	//find max
	fprintf( fOut, "\n//max value");
	int maxValue = arrayModule[0];
	for ( int i = 0; i < countModule; i++ )
		if ( maxValue < arrayModule[i] )
			maxValue = arrayModule[i];
	fprintf( fOut, "\nMAX_MD %d", maxValue < 0 ? 0 : (maxValue + 1) );
	maxValue = 0;
	maxValue = arrayFrame[0];
	for ( int i = 0; i < countFrame; i++ )
		if ( maxValue < arrayFrame[i] )
			maxValue = arrayFrame[i];
	fprintf( fOut, "\nMAX_FM %d", maxValue < 0 ? 0 : (maxValue + 1) );
	maxValue = 0;
	maxValue = arrayAnim[0];
	for ( int i = 0; i < countAnim; i++ )
		if ( maxValue < arrayAnim[i] )
			maxValue = arrayAnim[i];
	fprintf( fOut, "\nMAX_AN %d", maxValue < 0 ? 0 : (maxValue + 1) );

	fclose( fOut );
}

//Write file.h
void BuildSpriteClass ( char* spriteID, char * fileName )
{
	char* outClass = GetOutPutClassFileName( spriteID );
	char* outPak = GetOutPutPakFileName( spriteID );

	//char* nameClass = GetFileName( fileName );
	char line[100];
	int countFrame, countAnim;

	FILE *fOut = fopen ( outClass, "w" );
	//read from .pak
	FILE *fPak = fopen ( outPak, "r" );
	
	fprintf ( fOut, "#ifndef %s_h", spriteID );
	fprintf ( fOut, "\n#define %s_h\n", spriteID );
	fprintf ( fOut, "\nclass SPRITE_%s", strupr( spriteID ) );
	fprintf ( fOut, "\n{\npublic:");

	countFrame = 0;
	countAnim = 0;
	while (!feof( fPak ) )
	{
		fgets( line, sizeof( line ), fPak );
		if ( line[0] == 'F' && line[1] == 'R' && line[2] == 'A' && line[3] == 'M' && line[4] == 'E' )
		{
			char temp[10], name[50];
			sscanf( &line[1], "%s" "%s", &temp, &name );
			fprintf( fOut, "\n\tstatic const int FRAME_%s = %d;", strupr(name), countFrame);
			countFrame++;
		}
		else if ( line[0] == 'A' && line[1] == 'N' && line[2] == 'I' && line[3] == 'M')
		{
			char temp[10], name[50];
			sscanf( &line[1], "%s" "%s", &temp, &name );
			fprintf( fOut, "\n\tstatic const int ANIM_%s = %d;", strupr(name), countAnim);
			countAnim++;
		}

	}
	fprintf ( fOut, "\n};\n#endif");
	fclose (fOut);
	fclose (fPak);
}

//Build sprite
void BuildSpriteToPakFile (char* spriteID, char* fileName )
{
	//write data pak
	NameAndSize_Of_Image( spriteID, fileName );
	Modules( spriteID, fileName );
	Frames( spriteID, fileName );
	Anims( spriteID, fileName );
	MaxValue_MD_FR_AN ( spriteID );
}

//build all sprite
void BuildAllSpriteToPakFile ( vector <sprite> spriteList )
{
	for ( vector<sprite>::iterator i = spriteList.begin() ; i != spriteList.end() ; i++ )
	{		
		cout << endl << "Sprite building...: " << (*i).spriteName;
		BuildSpriteToPakFile( (*i).spriteID, (*i).spriteName );
	}			
}

//build all sprite to class
void BuildAllSpriteClass ( vector <sprite> spriteList )
{
	for ( vector<sprite>::iterator i = spriteList.begin() ; i != spriteList.end() ; i++ )
	{		
		BuildSpriteClass( (*i).spriteID, (*i).spriteName );
	}		
}

//include all sprite into SpritesInclude.h
void IncludeAllSprites ( vector <sprite> spriteList )
{	
	FILE* fOut = fopen( "SpritesInclude.h" , "w" );
	fprintf( fOut, "#ifndef SpritesInclude_h" );
	fprintf( fOut, "\n#define SpritesInclude_h\n" );
	for ( vector<sprite>::iterator i = spriteList.begin() ; i != spriteList.end() ; i++ )
	{
		cout << endl << "Include sprite...: " << (*i).spriteID << ".h";
		fprintf( fOut, "\n#include \"%s.h\"", (*i).spriteID );		
	}	
	fclose( fOut );	
}


//list sprite ID
void EnumListSprites ( vector <sprite> spriteList )
{
	int count = 0;
	FILE* fOut = fopen( "SpritesInclude.h" , "a" );

	fprintf ( fOut, "\n\nclass SPRITE_LIST\n{" );
	fprintf ( fOut, "\npublic:" );

	for ( vector<sprite>::iterator i = spriteList.begin() ; i != spriteList.end() ; i++ )
	{
		cout << endl << "SpriteID...: SPRITE_" << strupr((*i).spriteID);
		fprintf ( fOut, "\n\tstatic const int SPRITE_%s = %d;", strupr((*i).spriteID), count++ );		
	}
	//insert sprite numm
	fprintf ( fOut, "\n\tstatic const int SPRITE_MAX = %d;\n};", count );
	fprintf ( fOut, "\n#endif" );
	fclose (fOut );
}

//list sprite name
void ListSpriteName ( vector <sprite> spriteList )
{
	FILE* fOut = fopen( "SpritesInclude.cpp", "w" );

	fprintf ( fOut, "\n#include \"SpritesInclude.h\"" );
	fprintf ( fOut, "\n\nchar s_spritePackList[SPRITE_LIST::SPRITE_MAX][50] = \n{" );

	for ( vector<sprite>::iterator i = spriteList.begin() ; i != spriteList.end() ; i++ )
	{
		cout << endl << "SpriteID...: \"" << GetOutPutPakFileName( (*i).spriteID ) << "\"";
		fprintf ( fOut, "\n\t\"%s\",", GetOutPutPakFileName( (*i).spriteID ) );		
	}
	//insert sprite numm
	fprintf ( fOut, "\n};" );
	fclose (fOut );	
}


//read list 
vector < sprite > ReadList ( char* list )   
{
	vector <sprite> spriteList;

	char spriteID[50], spriteName[50], spritePath[256], temp[10];
	FILE* f = fopen ( list, "r");
	if ( f == NULL)
	{
		cout << endl << "Can not read file: " << list;
		return spriteList;
	}
	while ( !feof ( f ) )
	{
		fscanf ( f, "%s" "%s" "%s", &spriteID, &temp, &spritePath );

		if ( spriteID[0] == '\0' )
			continue;
		//spriteID
		for (int i = 0; i < strlen( spriteID ) - 2; i ++ )
			spriteID[i] = spriteID[i + 1];
		spriteID[ strlen( spriteID ) - 2 ] = '\0';

		//sprite name
		char temp[50]; 
			for (int i = strlen ( spritePath ) - 2; i >= 0; i-- )
			{	
				if ( spritePath[i] == '\\' )
				{
					temp[strlen ( spritePath ) - 2 - i] = '\0';
					break;
				}
				temp[strlen ( spritePath ) - 2 - i] = spritePath[i];
			}

			for (int i = strlen ( temp ) - 1; i >= 0; i-- )
			{	
				
				spriteName[strlen ( temp ) - 1 - i] = temp[i];
			}
			spriteName[strlen ( temp ) ] = '\0';		

			//push
			sprite _sprite;
			strcpy ( _sprite.spriteID, strupr(spriteID) );
			strcpy ( _sprite.spriteName, spriteName );
			if ( IsExist( spriteName ) && IsExist ( GetImageName (spriteName) ) )
			{
				spriteList.push_back ( _sprite );
			}
			else if ( !IsExist( spriteName ))
			{
				cout << endl <<  "------------  " << spriteName << " not exist";
			}
			else if ( !IsExist ( GetImageName (spriteName)) )
			{
				cout << endl <<  "------------  " << spriteName << " null image";
			}			

			memset ( spriteID, 0, sizeof (spriteID) );
			memset ( spriteName, 0, sizeof (spriteName) );
			memset ( spritePath, 0, sizeof (spritePath) );
	}

	fclose ( f );
	return spriteList;
}


void BuildSpitesAndInclude ( char* list )
{
	if ( !IsExist (list) )
	{
		cout << endl << "Can not read list: " << list ;
		return;
	}

	vector <sprite> spriteList;
	spriteList = ReadList ( list );

	BuildAllSpriteToPakFile ( spriteList );
	BuildAllSpriteClass ( spriteList );
	IncludeAllSprites ( spriteList );
	EnumListSprites ( spriteList );
	ListSpriteName ( spriteList );
}


void main ( int argv, char* arg[] )
{	
	//BuildSpitesAndInclude ( "sprites.list" );	
	BuildSpitesAndInclude ( arg[1] );		
	cout << endl ;
	//system("pause");
	
}